Skip to content

Conversation

typotter
Copy link
Collaborator

@typotter typotter commented Feb 19, 2025


labels: mergeable

Fixes: #issue

Motivation and Context

Accessing the underlying configuration values is complex (it relies on several IConfigurationStore instances) and as a result, requires a couple of one-off orphan functions and oddly located helper methods to interact with the configuration objects. All of this implementation detail leaks into the EppoClient

Description

new interface:

export interface IConfiguration {
  getFlag(key: FlagKey | HashedFlagKey): Flag | ObfuscatedFlag | null;
  getFlags(): Record<FlagKey | HashedFlagKey, Flag | ObfuscatedFlag>;
  getBandits(): Record<BanditKey, BanditParameters>;
  getBanditVariations(): Record<FlagKey | HashedFlagKey, BanditVariation[]>;
  getFlagBanditVariations(flagKey: FlagKey | HashedFlagKey): BanditVariation[];
  getFlagVariationBandit(flagKey: FlagKey | HashedFlagKey, variationValue: string): BanditParameters | null;
  getBandit(key: BanditKey): BanditParameters | null;
  getFlagConfigDetails(): ConfigDetails;
  getFlagKeys(): FlagKey[] | HashedFlagKey[];
  isObfuscated(): boolean;
  isInitialized(): boolean;
}

An instance of this interface is available from the ConfigurationRequestor (a default instance is created if the config requestor has not been instantiated yet).

Each call into the EppoClient that requires config access first gets the current IConfiguration then uses that config object throughout the callstack.

For now, the IConfiguration instance is backed by the various config stores, so all this PR does is move access from the stores directly to corresponding methods on the IConfiguration instance.

How has this been tested?

  • Tests for the new classes and methods
  • existing tests continue to function unchanged with the refactoring

What's left to do

Because the config is backed by the stores which are written to by the ConfigRequestor, the configuration can actually change during a call-in computation. As such, the next step in this process will be to introduce a ReadOnlyConfiguration that will be a snapshot of the config instead of a life object.

Copy link
Contributor

@aarsilv aarsilv left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👏👏👏 BRAVO 👏👏👏

This is MUCH cleaner 🧹 🧹 🧹 Huge improvement for these files and I really appreciate the additional tests as well 💪 💪 💪

👨‍🍳 👌

});

describe('getConfiguration', () => {
it('should return an empty configuration instance before a config has been loaded', async () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

jest.restoreAllMocks();
});

describe('getConfiguration', () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🙌

private readonly banditModelConfigurationStore: IConfigurationStore<BanditParameters> | null,
) {}
) {
this.configuration = new StoreBackedConfiguration(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice

import { BanditParameters, BanditVariation, Environment, Flag, ObfuscatedFlag } from './interfaces';
import { BanditKey, FlagKey } from './types';

describe('StoreBackedConfiguration', () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🙌

IHttpClient,
IUniversalFlagConfigResponse,
} from './http-client';
import { StoreBackedConfiguration } from './i-configuration';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this i-* file pattern for interfaces. Helps separate out functionally related interfaces, vs putting them all in one large file

@typotter
Copy link
Collaborator Author

👏👏👏 BRAVO 👏👏👏

This is MUCH cleaner 🧹 🧹 🧹 Huge improvement for these files and I really appreciate the additional tests as well 💪 💪 💪

👨‍🍳 👌

Thank you, thank you very much ?:

@typotter typotter merged commit 4679cfd into main Feb 21, 2025
8 checks passed
@typotter typotter deleted the tp/i-configuration branch February 21, 2025 05:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants